package com.example;

import org.junit.jupiter.api.Test;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * 我们探寻了怎样创建 CompletableFuture，转换它们，并组合多个 CompletableFuture。
 * 现在让我们弄明白当发生错误的时候我们应该怎么做。
 */
public class Demo05Test {


    /**
     * 首先让我们明白在一个回调链中错误是怎么传递的。思考下以下回调链：
     * 如果在原始的 supplyAsync() 任务中发生一个错误，这时候没有任何 thenApply 会被调用并且 future 将以一个异常结束。
     * 如果在第一个 thenApply 发生错误，这时候第二个和第三个将不会被调用，同样的，future 将以异常结束。
     */
    @Test
    public void test01() throws ExecutionException, InterruptedException {
        // do something with the final result
        CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
            // Code which might throw an exception
            System.out.println("begin");
            return "Some result";
        }).thenApply(result -> {
            System.out.println(result);
            return "processed result";
        }).thenApply(result -> {
            System.out.println(result);
            return "result after further processing";
        }).thenAccept(System.out::println);

        future.get();
    }

    /**
     * 使用 exceptionally() 回调处理异常 exceptionally() 回调给你一个从原始 Future 中生成的错误恢复的机会。
     * 你可以在这里记录这个异常并返回一个默认值。
     */
    @Test
    public void test02() throws ExecutionException, InterruptedException {
        int age = -1;
        CompletableFuture<String> resFuture = CompletableFuture.supplyAsync(() -> {
            if (age < 0) {
                throw new IllegalArgumentException("年龄不能小于0");
            }
            if (age >= 18) {
                return "成人";
            } else {
                return "小孩";
            }
        }).exceptionally(ex -> {
            System.out.println("Oops! We have an exception - " + ex.getMessage());
            return "未知";
        });

        System.out.println("res: " + resFuture.get());
    }

    /**
     * 使用 handle() 方法处理异常 API提供了一个更通用的方法 - handle()从异常恢复，无论一个异常是否发生它都会被调用。
     */
    @Test
    public void test03() throws ExecutionException, InterruptedException {
        int age = -1;
        CompletableFuture<String> resFuture = CompletableFuture.supplyAsync(() -> {
            if (age < 0) {
                throw new IllegalArgumentException("年龄不能小于0");
            }
            if (age >= 18) {
                return "成人";
            } else {
                return "小孩";
            }
        }).handle((res,ex) -> {
            // 如果异常发生，res参数将是 null，否则，ex将是 null。
            if (ex != null) {
                System.out.println("Oops! We have an exception - " + ex.getMessage());
                return "未知";
            }
            return res;
        });

        System.out.println("res: " + resFuture.get());
    }
}
